/**
******************************************************************************************
* @file subject.c
* @brief Design pattern Observer.
* @date 14 avril 2015
* @author Benjamin Lancinot / Ciro S. Costa
*****************************************************************************************/
/* COPYRIGHT ****************************************************************************
*****************************************************************************************
* Written By Ciro S. Costa /Adapted by Benjamin Lancinot
*
* The MIT License (MIT)
*
* Copyright (c) <2014>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
* software and associated documentation files (the "Software"), to deal in the Software
* without restriction, including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
********************************************************************************************/

#include "subject.h"

/*******************************************************************************************
* PROTOTYPES
********************************************************************************************/

Subject * subjectNew(void*, int);

static void _destroy(Subject*);

int _registerObserver(Subject*, Observer*);

int _unregisterObserver(Subject *, Observer*);

void _notifyObservers(Subject*);

/*******************************************************************************************
* FUNCTIONS
********************************************************************************************/

/**
 * @brief Constructor
 * @param impl Pointer to object which are the subject
 * @param type Specific type of subject
 * @return The pointer to the new Subject
 **/
Subject * subjectNew(void* impl, int type)
{
	Subject* this = (Subject *) calloc(1,sizeof(*this));

	this->destroy = _destroy;
	this->impl = impl;
	this->type = type;
	this->registerObserver = _registerObserver;
	this->unregisterObserver = _unregisterObserver;
	this->notifyObservers = _notifyObservers;

	return this;
}

/**
 * @brief Destructor
 * @param This Pointer to the wanted Subject
 **/
static void _destroy(Subject* this)
{
	if (this != NULL) {
		free(this);
		this = NULL;
	}
}

/**
 * @brief Add an observer for a specific subject
 * @param this Pointer to the specific subject
 * @param observer Pointer to the observer to add
 * @return the developpment of the registration
 **/
int _registerObserver(Subject* this, Observer* observer)
{
	int i=0;
        int run = -1;

        while (run == -1) {
		if (this->observers[i] == NULL) {
			this->observers[i] = observer;
                        run = OK;
		}
                i++;
                if (i == 20){
                        run = KO;
		}
	}
	return run;
}

/**
 * @brief Remove an observer for a specific subject
 * @param this Pointer to the specific subject
 * @param observer Pointer to the observer to add
 * @return the developpment of the unregistration
 **/
int _unregisterObserver(Subject *this, Observer* observer)
{
	int i;

	for(i=0 ; i < 20; i++) {
		void* pObserver = this->observers[i];

		if (observer == pObserver) {
			this->observers[i] = NULL;
			return OK;
		}
	}

	return KO;
}

/**
 * @brief Call notify methods of alls observers of this specific subject
 * @param this Pointer to the specific subject
 **/
void _notifyObservers(Subject* this)
{
	int i;

	for (i=0; i < 20; i++) {
		if (this->observers[i] != NULL) {
			this->observers[i]->notify(this->observers[i], this->type, this->impl);
		}
	}
}

